package common;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Vector;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.NsIterator;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;


public class SkillManInstance 
{
	public static String myNS="http://www.unisa.it/skill_management.owl#";
	public static String cvNS="http://kaste.lv/~captsolo/semweb/resume/cv.rdfs#";
	//private static String nothing="http://www.w3.org/2002/07/owl#Nothing";
	public static String foafNS="http://xmlns.com/foaf/0.1/";
	public static String rdfNS="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
	private String cwd="";
	private String filename;
	private OntModel onto;
	private SkillManSchema schema;
	private String def="";
	
	public SkillManInstance( SkillManSchema schema, String filename )
	{
		this.schema=schema;
		onto = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_RDFS_INF, null );
		this.filename=filename;
	}
	
	public boolean load() throws FileNotFoundException
	{
		onto.read("file:"+cwd+filename, "");
		NsIterator it=onto.listNameSpaces();
		if( it==null )
			return false;
		
		while( it.hasNext() )
		{
			if( it.next().toString().contains("http://www.unisa.it/skill_management.owl") )
				return true;
		}
		
		return false;
	}
	
	public boolean loadDefault(String defInst) throws FileNotFoundException
	{		
		def=defInst;
		
		File f=new File(cwd+filename);
		if( f.exists() )
		{
			System.out.println("Error: Instance file already exists. Loading that.");
			load();
			return false;
		}
		
		onto.read("file:"+def, "");
		return true;
	}
	
	public void store() throws FileNotFoundException
	{				
		FileOutputStream fp=new FileOutputStream( new File(cwd+filename) );
		onto.write(fp);		
	}
	
	public OntClass getOntClass(String cl)
	{
		OntClass cls=onto.getOntClass(cl);
		
		if( cls==null )
			cls=onto.getOntClass(cvNS+cl);
		
		if( cls==null )
			cls=onto.getOntClass(myNS+cl);
		
		if( cls==null ){
			System.out.println("Class not found: "+cl);
			System.out.println("file: "+filename);
		}
		
		return cls;
	}
	
	public boolean addSkill(OntClass parent, int lvl)
	{
		if( parent==null ){
			System.out.println("Class is null...");
			return false;
		}
		
		if( !schema.existsSkill(parent) )
		{
			System.out.println("Invalid skill: skill not present in the taxonomy.");
			return false;
		}
		
		if( lvl<1 || lvl>5 )
		{
			System.out.println("Invalid skill level.");
			return false;
		}
		
		OntClass grParent=parent.getSuperClass();
		if(  !grParent.getLocalName().equals("Thing") && getSkillLevel(grParent)==0 )
			addSkill(grParent, lvl);

		
		Individual i=firstInstanceOf(parent);
		
		i.setPropertyValue( onto.getProperty(cvNS+"skillLevel") , onto.createLiteral(""+lvl));
		return true;
	}
	
	public boolean addSkill(String strParent, int lvl)
	{
		OntClass parent=getOntClass(strParent);
		return addSkill(parent, lvl);
	}

	public boolean setPropertyValue(String cl, String prp, String value) 
	{		
		OntClass p=onto.getOntClass(cl);
		Individual pi=firstInstanceOf(p);
		
		pi.setPropertyValue( onto.getProperty(prp) , onto.createLiteral(value));
		
		return true;
	}
	
	public String getProperyValue( String cl, String prop )
	{
		OntClass p=onto.getOntClass(cl);
		Individual pi=getFirstInstanceOf(p);
		String value="";
		try{
			value=pi.getPropertyValue( onto.getProperty(prop) ).toString();
		}
		catch( NullPointerException e )
		{
			System.out.println("ERROR: property '"+prop+"' of class '"+cl+"' not found.");
		}
		
		return value;
	}
	
	private Individual firstInstanceOf(OntClass cl)
	{
		Individual i;
		ExtendedIterator it=cl.listInstances(true);
		if( it.hasNext() )
		{
			System.out.println(cl.getLocalName()+": instance already present. Returning that.");
			i=(Individual)it.next();
		}
		else
		{
			System.out.println(cl.getLocalName()+": new instance created.");
			i=cl.createIndividual();
		}
		return i;
	}
	
	private Individual getFirstInstanceOf( OntClass cl )
	{
		Individual i=null;
		ExtendedIterator it=cl.listInstances(true);
		if( it.hasNext() )
		{
			System.out.println(cl.getLocalName()+": instance found. Returning that.");
			i=(Individual)it.next();
		}
		
		return i;
	}
	
	public int getSkillLevel( OntClass parent )
	{
		if( parent==null )
			return 0;
		
		Individual i=getFirstInstanceOf(parent);
		
		if( i==null )
		{
			System.out.print(getProperyValue(SkillManInstance.foafNS+"Person", SkillManInstance.foafNS+"name")+": ");
			System.out.println("Invalid instance of: "+parent.getURI());
			return 0;
		}
		
		int lvl;
		try{
			lvl=Integer.parseInt( i.getPropertyValue( onto.getProperty(cvNS+"skillLevel") ).toString() );
		}
		catch( NumberFormatException e )
		{
			System.out.println("Invalid skill/skill level.");
			return 0;
		}
		
		return lvl;
	}
	
	public int getSkillLevel( String skill )
	{
		OntClass parent=getOntClass(skill);
		return getSkillLevel(parent);
	}
	
	// prende in input l'istanza della ricerca.
	public float compareTo( SkillManInstance base )
	{
		ExtendedIterator itr=base.getInstances(cvNS+"Skill");

		int j=0;
		int scarto=0;
		while( itr.hasNext() )
		{
			Individual in=(Individual)itr.next();
			String uri= in.getPropertyValue( onto.getProperty(rdfNS+"type") ).toString();
			int lvl1=base.getSkillLevel(uri);
			int lvl2=getSkillLevel(uri);
			System.out.println("Base. "+uri+" = "+lvl1);
			if( lvl2==0 )
			{
				//lvl2=getSkillLevel( base.getOntClass(uri).getSuperClass() )/2;
				//System.out.println("Instance. Skill not found. Comparing with parent/2: "+base.getOntClass(uri).getSuperClass().getLocalName()+" = "+lvl2);
				System.out.println("Instance. Skill not found.");
			}
			else
			{
				System.out.println("Instance. "+uri+" = "+lvl2);
			}
			
			// sarà negativo
			if( lvl2<lvl1 )
				scarto+=lvl1-lvl2;
			j++;
		}
		
		// 100:(j*5)=x:(j*5-scarto) => x=100*(j*5-scarto)/(j*5)
		float perc=(float)100*(j*5-scarto)/(j*5);
		return perc;
	}
	
	public Vector<MySkill> getSkills( )
	{
		ExtendedIterator itr=getInstances(cvNS+"Skill");
		Vector<MySkill> skills=new Vector<MySkill>();
		
		while( itr.hasNext() )
		{
			Individual in=(Individual)itr.next();
			String uri= in.getPropertyValue( onto.getProperty(rdfNS+"type") ).toString();
			int lvl=getSkillLevel(uri);
			MySkill skill=new MySkill();
			skill.skill= uri.substring( uri.lastIndexOf("#")+1 );
			skill.lvl=lvl;
			skills.add(skill);
		}
	
		return skills;
	}
	
	private ExtendedIterator getInstances( String s )
	{
		OntClass cl=getOntClass(s);
		return cl.listInstances(false);
	}
	
	public boolean setCWD(String dir)
	{
		if( !dir.equals("") && dir.charAt( dir.length()-1 )!='/' )
			dir+="/";
		
		File fp=new File(dir+".");
		if( !fp.exists() || !fp.canWrite() )
		{
			System.out.println("WARN: Unreadable CWD. Using default.");
			return false;
		}
		
		System.out.println("CWD: "+dir);
		cwd=dir;
		return true;
	}
	
}

